package com.eralink.unionuhfreader;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.eralink.unionuhfreader.adapter.FinderReportReaderListViewAdapter;
import com.eralink.unionuhfreader.bean.FinderReportReaderBean;
import com.eralink.unionuhfreader.util.CacheNode;
import com.eralink.unionuhfreader.util.CachePool;
import com.eralink.unionuhfreader.util.ReaderFinderReportDataParseUtil;
import com.eralink.unionuhfreader.util.Utils;
import com.eralink.readerfinderlib.EraLinkReaderFinderApiError;
import com.eralink.readerfinderlib.EraLinkReaderFinderInterface;
import com.eralink.readerfinderlib.EraLinkReaderReportCallback;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

public class NetReaderFindActivity extends AppCompatActivity {
    private Button btnStartReaderFinder;
    private Button btnStopReaderFinder;
    private Button btnDiscoveryReader;
    private CheckBox chkEnableDhcp;
    private EditText edtIp;
    private EditText edtMask;
    private EditText edtGateway;
    private EditText edtPort;
    private Spinner spinnerNetMode;
    private EditText edtServerIp;
    private EditText edtServerPort;
    private Button btnGetReaderNetConfig;
    private Button btnSetReaderNetConfig;
    private Button btnRestartReader;

    private final Object syncObj = new Object();
    private final List<FinderReportReaderBean> finderReportReaderBeanList = new LinkedList<>();
    private final Hashtable<String, FinderReportReaderBean> readerBeanMap = new Hashtable<>() ;
    private FinderReportReaderListViewAdapter finderReportReaderListViewAdapter;

    private static final int cmd_reader_discovery_report = 0x01;

    private String selectedReaderMacAddress = null;

    private Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.net_reader_find_activity);

        intent = getIntent();

        btnStartReaderFinder = findViewById(R.id.btn_start_reader_finder);
        btnStopReaderFinder = findViewById(R.id.btn_stop_reader_finder);
        btnDiscoveryReader = findViewById(R.id.btn_discovery_reader);
        btnStartReaderFinder.setOnClickListener(v -> startReaderFinderAction());
        btnStopReaderFinder.setOnClickListener(v -> stopReaderFinderAction());
        btnDiscoveryReader.setOnClickListener(v -> discoveryReaderAction());

        ListView lvReader = findViewById(R.id.lv_finder_report_reader);
        finderReportReaderListViewAdapter = new FinderReportReaderListViewAdapter(this, finderReportReaderBeanList);
        lvReader.setAdapter(finderReportReaderListViewAdapter);
        lvReader.setOnItemClickListener((parent, view, position, id) -> {
            selectedReaderMacAddress = finderReportReaderBeanList.get(position).getMac();
            finderReportReaderListViewAdapter.setSelectedItem(position);
            finderReportReaderListViewAdapter.notifyDataSetInvalidated();
        });

        chkEnableDhcp = findViewById(R.id.chk_enable_dhcp);
        edtIp = findViewById(R.id.edt_reader_ip);
        edtMask = findViewById(R.id.edt_mask);
        edtGateway = findViewById(R.id.edt_gateway);
        edtPort = findViewById(R.id.edt_port);
        spinnerNetMode = findViewById(R.id.spinner_net_mode);
        edtServerIp = findViewById(R.id.edt_server_ip);
        edtServerPort = findViewById(R.id.edt_server_port);
        chkEnableDhcp.setOnClickListener(v -> {
            edtIp.setEnabled(!chkEnableDhcp.isChecked());
            edtMask.setEnabled(!chkEnableDhcp.isChecked());
            edtGateway.setEnabled(!chkEnableDhcp.isChecked());
        });

        btnGetReaderNetConfig = findViewById(R.id.btn_get_reader_net_config);
        btnSetReaderNetConfig = findViewById(R.id.btn_set_reader_net_config);
        btnRestartReader = findViewById(R.id.btn_restart_reader);
        btnGetReaderNetConfig.setOnClickListener(v -> getReaderNetConfigAction());
        btnSetReaderNetConfig.setOnClickListener(v -> setReaderNetConfigAction());
        btnRestartReader.setOnClickListener(v -> restartReaderAction());
        Button btnConfirm = findViewById(R.id.btn_confirm);
        Button btnCancel = findViewById(R.id.btn_cancel);
        btnConfirm.setOnClickListener(v -> confirmAction());
        btnCancel.setOnClickListener(v -> cancelAction());

        enableButtons(false);
    }

    private void startReaderFinderAction() {
        final int result = EraLinkReaderFinderInterface.getInstance().open((short) 17776);
        Toast.makeText(this, String.format("启动读写器发现指令结果：%s", result), Toast.LENGTH_SHORT).show();
        if (EraLinkReaderFinderApiError.Err_no_error.getValue() != result) {
            return;
        }

        EraLinkReaderFinderInterface.getInstance().setDeviceReportCallback(new EraLinkReaderReportCallback() {
            @Override
            public void report(byte[] report_data, int report_data_len) {
                // System.out.printf("device report: %s\n", Utils.bytesToHexString(report_data, 0, report_data_len));
                System.out.printf("device: %s\n", new String(report_data, 0, report_data_len));
                CacheNode cacheNode = CachePool.getInstance().obtain(report_data_len);
                System.arraycopy(report_data, 0, cacheNode.getBuffer(), 0, report_data_len);
                cacheNode.setBufferSize(report_data_len);

                Message message = new Message();
                message.what = cmd_reader_discovery_report;
                message.obj = cacheNode;
                readerDiscoveryReportHandler.sendMessage(message);
            }
        });

        enableButtons(true);
    }

    private void enableButtons(boolean opened) {
        btnStartReaderFinder.setEnabled(!opened);
        btnStopReaderFinder.setEnabled(opened);
        btnDiscoveryReader.setEnabled(opened);
        btnGetReaderNetConfig.setEnabled(opened);
        btnSetReaderNetConfig.setEnabled(opened);
        btnRestartReader.setEnabled(opened);
    }

    private void stopReaderFinderAction() {
        EraLinkReaderFinderInterface.getInstance().close();
        enableButtons(false);
    }

    private void discoveryReaderAction() {
        selectedReaderMacAddress = null;
        readerBeanMap.clear();
        finderReportReaderBeanList.clear();
        finderReportReaderListViewAdapter.setSelectedItem(-1);
        finderReportReaderListViewAdapter.notifyDataSetChanged();
        final int result = EraLinkReaderFinderInterface.getInstance().discovery();
        Toast.makeText(this, String.format("获取读写器网络参数结果：%s", result), Toast.LENGTH_SHORT).show();
    }

    private void restartReaderAction() {
        if (selectedReaderMacAddress == null) {
            return;
        }

        EraLinkReaderFinderInterface.getInstance().restart(selectedReaderMacAddress);
    }

    private void getReaderNetConfigAction() {
        if (selectedReaderMacAddress == null) {
            return;
        }

        final String[] net_config = new String[1];
        final int result = EraLinkReaderFinderInterface.getInstance().getNetConfig(selectedReaderMacAddress, net_config);
        if (EraLinkReaderFinderApiError.Err_no_error.getValue() == result) {
            HashMap<String, String> items = new HashMap<>();
            ReaderFinderReportDataParseUtil.parse(net_config[0], items);
            final boolean enableDhcp = items.get("dhcp").equals("1");
            chkEnableDhcp.setChecked(enableDhcp);
            edtIp.setText(items.get("ip"));
            edtMask.setText(items.get("mask"));
            edtGateway.setText(items.get("gateway"));
            edtIp.setEnabled(!enableDhcp);
            edtMask.setEnabled(!enableDhcp);
            edtGateway.setEnabled(!enableDhcp);
            edtPort.setText(items.get("port"));
            String net_mode = items.get("net_mode");
            if (net_mode == null) {
                net_mode = "1";
            }
            spinnerNetMode.setSelection(Integer.parseInt(net_mode));

            final String server_ip = items.get("server_ip");
            spinnerNetMode.setEnabled(server_ip != null);
            edtServerIp.setText(server_ip == null? "" : server_ip);
            edtServerIp.setEnabled(server_ip != null);
            final String server_port = items.get("server_port");
            edtServerPort.setText(server_port == null ? "" : server_port);
            edtServerPort.setEnabled(server_port != null);

            synchronized (syncObj) {
                FinderReportReaderBean bean = readerBeanMap.get(selectedReaderMacAddress);
                if (bean != null) {
                    bean.setPort(Integer.parseInt(items.get("port")));
                    bean.setBaud(Integer.parseInt(items.get("baud")));
                    bean.setParity(Integer.parseInt(items.get("parity")));
                    bean.setDatabits(Integer.parseInt(items.get("databits")));
                    bean.setStopbis(Integer.parseInt(items.get("stopbits")));
                    String product_code = items.get("product_code");
                    if (product_code != null) {
                        bean.setProduct_code(Integer.parseInt(product_code));
                    }
                }
            }
        }
        Toast.makeText(this, String.format("获取读写器网络参数结果：%s", result), Toast.LENGTH_SHORT).show();
    }

    private void setReaderNetConfigAction() {
        if (selectedReaderMacAddress == null) {
            return;
        }

        final String[] net_config = new String[1];
        if (!buildNetConfig(net_config)) {
            return;
        }
        System.err.printf("build net config: %s\n", net_config[0]);
        final int result = EraLinkReaderFinderInterface.getInstance().setNetConfig(selectedReaderMacAddress, net_config[0]);
        Toast.makeText(this, String.format("设置读写器网络参数结果：%s", result), Toast.LENGTH_SHORT).show();
    }

    private boolean buildNetConfig(final String[] net_config) {
        final String ip = edtIp.getText().toString().trim();
        final String mask = edtMask.getText().toString().trim();
        final String gateway = edtGateway.getText().toString().trim();
        final String port = edtPort.getText().toString().trim();
        if (!Utils.ipCheck(ip) || !Utils.ipCheck(mask) || !Utils.ipCheck(gateway) || !Utils.isValidPort(port)) {
            return false;
        }

        String server_ip = null;
        String server_port = null;
        if (edtServerIp.isEnabled()) {
            server_ip = edtServerIp.getText().toString().trim();
            server_port = edtServerPort.getText().toString().trim();
            if (!Utils.ipCheck(server_ip) || !Utils.isValidPort(server_port)) {
                return false;
            }
        }

        StringBuilder builder = new StringBuilder();
        builder.append(String.format("dhcp=%s;gateway=%s;mask=%s;ip=%s;port=%s",
                chkEnableDhcp.isChecked()? 1 : 0, gateway, mask, ip, port));

        synchronized (syncObj) {
            FinderReportReaderBean bean = readerBeanMap.get(selectedReaderMacAddress);
            if (bean == null || bean.getBaud() == -1) {
                return false;
            }

            builder.append(String.format(";baud=%s;parity=%s;databits=%s;stopbits=%s",
                    bean.getBaud(), bean.getParity(), bean.getDatabits(), bean.getStopbis()));
            if (bean.getProduct_code() != -1 && server_ip != null) {
                builder.append(String.format(";server_ip=%s;server_port=%s;net_mode=%s;product_code=%s",
                        server_ip, server_port, spinnerNetMode.getSelectedItemId(), bean.getProduct_code()));
            }
        }

        net_config[0] = builder.toString();

        return true;
    }

    private void confirmAction() {
        if (selectedReaderMacAddress != null) {
            synchronized (syncObj) {
                FinderReportReaderBean bean = readerBeanMap.get(selectedReaderMacAddress);
                if (bean != null) {
                    intent.putExtra("reader", String.format("%s:%s", bean.getIp(), String.valueOf(bean.getPort())));
                    setResult(RESULT_OK, intent);
                }
            }
        }
        finish();
    }

    private void cancelAction() {
        finish();
    }

    @Override
    protected void onStop() {
        super.onStop();

        stopReaderFinderAction();
    }

    private static class DeviceDiscoveryReportHandler extends Handler {
        private final WeakReference<NetReaderFindActivity> mainActivityWeakReference;

        public DeviceDiscoveryReportHandler(NetReaderFindActivity mainActivity) {
            mainActivityWeakReference = new WeakReference<>(mainActivity);
        }

        public void handleMessage(Message msg) {
            if (msg.what == cmd_reader_discovery_report) {
                processReaderReport((CacheNode) msg.obj);
            }
        }

        private void processReaderReport(CacheNode cacheNode) {
            NetReaderFindActivity mainActivity = mainActivityWeakReference.get();
            if (mainActivity == null) {
                return;
            }

            final HashMap<String, String> items = new HashMap<>();
            final String report_data = new String(cacheNode.getBuffer(), 0, cacheNode.getBufferSize());
            ReaderFinderReportDataParseUtil.parse(report_data, items);
            CachePool.getInstance().release(cacheNode);

            final String ip = items.get("ip");
            final String mac_address = items.get("mac_address");
            final String version = items.get("version");
            final String name = items.get("name");
            final String net_mode = items.get("net_mode");

            synchronized (mainActivity.syncObj) {
                FinderReportReaderBean finderReportReaderBean = mainActivity.readerBeanMap.get(mac_address);
                if (finderReportReaderBean == null) {
                    finderReportReaderBean = new FinderReportReaderBean();
                    finderReportReaderBean.setIndex(mainActivity.readerBeanMap.size());
                    finderReportReaderBean.setMac(mac_address);
                    mainActivity.readerBeanMap.put(mac_address, finderReportReaderBean);
                    mainActivity.finderReportReaderBeanList.add(finderReportReaderBean);
                }

                finderReportReaderBean.setIp(ip);
                finderReportReaderBean.setVersion(version);
                finderReportReaderBean.setName(name);
                if (net_mode == null) {
                    finderReportReaderBean.setNetMode(1);
                } else {
                    finderReportReaderBean.setNetMode(Integer.parseInt(net_mode));
                }
            }

            mainActivity.finderReportReaderListViewAdapter.notifyDataSetChanged();
        }
    }

    private final Handler readerDiscoveryReportHandler = new DeviceDiscoveryReportHandler(this);
}